/*
    Coder : Dzlua
    Email : 505544956@qq.com
    Time  : 2017/07/04
*/
#pragma once

#include <string>
#include "utils.h"

#define AV_MAX_QUEUE_SIZE 100
#define AV_SLEEP_TIME_AFTER_QUEUE_FULL 50
#define AV_DELAY_TIME_LAST_FRAME 40

namespace dzlua {
namespace av {

enum class eDataType : uint8_t {
    video, audio, subtitle
};

enum class eUseDecoder : uint8_t {
    nouse, use, nochange
};

//------------------------------//
/*
*   pixel format for video
*   see ffmpeg: pixfmt.h
*/
enum class ePixelFormat : uint16_t {
    unknown, yuv420p, rgb24, bgr24,
    argb, rgba, abgr, bgra, // 8888
};

/*
*    algorithms for video
*/
enum class eAlgorithm : uint16_t {
    fast_bilinear, bilinear, bicubic,
    x, point, area, bicublin, gauss,
    sinc, lanczos, spline
};

/*
*    video infos
*/
struct VideoInfo {
    ePixelFormat format;
    eAlgorithm algorithm;
    int width;
    int height;
};

/*
*    video data
*/
struct VideoData : public VideoInfo {
    uint8_t *data[4];
    int linesize[4];
    uint64_t pts;
    /*
    *   time will be show
    *   second
    */
    double time;

    /*
    *   time frome this time to next time.
    *   deay = (time - last_time) * 1000.
    *   millisecond
    */
    uint32_t delay;
    VideoData(const VideoInfo *info);
};

//------------------------------//
/*
*    Audio channel layouts
*/
enum class eChannelLayout : uint8_t {
    native, mono, stereo, _2point1, _2_1,
    surround, _3point1, _4point0, _4point1, _2_2,
    quad, _5point0, _5point1, _5point0_back, _5point1_back,
    _6point0, _6point0_front, hexagonal,
    _6point1, _6point1_back, _6point1_front,
    _7point0, _7point0_front, _7point1, _7point1_wide, _7point1_wide_back,
    octagonal, hexadecagonal, stereo_downmix 
};

/*
*    Audio sample formats
*/
enum class eSampleFormat : uint8_t {
    none, u8, s16, s32, flt, dbl, s64,
    u8p, s16p, s32p, fltp, dblp, s64p
};

/*
*    Audio infos
*/
struct AudioInfo {
    /*
    *   read write
    */
    eChannelLayout layout;
    eSampleFormat format;
    int rate;
    int channels;
    /*
    *   read only
    */
    int samples;
};

/*
*    audio data
*/
struct AudioData : public AudioInfo {
    uint8_t *data;
    int linesize;
    int size;
    uint64_t pts;
    double time;
    AudioData(const AudioInfo *info);
};

//------------------------------//
/*
*    Subtitle infos
*/
struct SubtitleInfo {};

/*
*    subtitle data
*/
struct SubtitleData {
    std::string text;
};

class Decoder {
public:
    /*
    *   get a new interface to use Decoder.
    */
    static std::shared_ptr<Decoder> NewInterface();
public:
    /*
    *   init with max decoder queue size for all queues.
    *   and sleep time after queue is full.
    */
    virtual bool Init(size_t max_queue_size = AV_MAX_QUEUE_SIZE
                    , size_t sleep_time = AV_SLEEP_TIME_AFTER_QUEUE_FULL) = 0;

    /*
    *   open a file, it will call Close if not closed.
    */
    virtual bool Open(const std::string &filename) = 0;

    /*
    *   set video,audio,subtitle as no use.
    *   false do nothing.
    */
    virtual void SetNoUse(bool setVideo = false, bool setAudio = false, bool setSubtitle = false) = 0;

    /*
    *   close file, decode thread not end.
    */
    virtual void Close() = 0;

    /*
    *   decoder run.
    */
    virtual void Run() = 0;

    /*
    *   stop decoder.
    *   it will close the open file 
    *       and end the life of all decoder threads.
    */
    virtual void Stop() = 0;

    /*
    *   all threads pause
    */
    virtual void Pause() = 0;

    /*
    *   the same as run.
    */
    virtual void Continue() = 0;

    /*
    *   seek to the pos.
    */
    virtual void Seek(double pos) = 0;

    /*
    *   get the duration of the file.
    */
    virtual double Duration() = 0;

    /*
    *   wait threads end.
    */
    virtual void Wait() = 0;

    /*
    *   wait current file deocde done.
    */
    virtual void WaitDone() = 0;

    /*
    *   if the file deocde done.
    */
    virtual bool IsDone() = 0;
public:
    /*
    *   set decode format
    *   use setInfo, must be ensure not run.
    *   nullptr for raw data.
    */
    virtual void setInfo(const VideoInfo *info) = 0;
    
    /*
    *   set decode format
    *   use setInfo, must be ensure not run.
    *   nullptr for raw data.
    */
    virtual void setInfo(const AudioInfo *info) = 0;
    
    /*
    *   set decode format
    *   use setInfo, must be ensure not run.
    *   nullptr for raw data.
    */
    virtual void setInfo(const SubtitleInfo *info) = 0;
    
    /*
    *   get raw data info
    *   called after open.
    */
    virtual std::shared_ptr<VideoInfo> getVideoInfo() = 0;

    /*
    *   get raw data info
    *   called after open.
    */
    virtual std::shared_ptr<AudioInfo> getAudioInfo() = 0;

    /*
    *   get raw data info
    *   called after open.
    */
    virtual std::shared_ptr<SubtitleInfo> getSebtitleInfo() = 0;
public:
    /*
    *   get a frame of decoded video data.
    */
    virtual std::shared_ptr<VideoData> pop_video_data() = 0;

    /*
    *   get a frame of decoded audio data.
    */
    virtual std::shared_ptr<AudioData> pop_audio_data() = 0;

    /*
    *   get a frame of decoded subtitle data.
    */
    virtual std::shared_ptr<SubtitleData> pop_subtitle_data() = 0;

    /*
    *   if the queue of eDataType is empty.
    */
    virtual bool empty(eDataType edt) = 0;

    /*
    *   get the queue size of eDataType.
    */
    virtual size_t size(eDataType edt) = 0;

    /*
    *   clear the queue of eDataType.
    */
    virtual void clear(eDataType edt) = 0;
};

//------------------------------//
void log(const std::string msg);

} // end namespace av
} // end namespace dzlua